"use strict";

//$$animateReflow in angular-animate

app.factory("CropService", ["$rootScope", "$timeout", "$window", "$$rAF", "$q", "imageService", function ($rootScope, $timeout, $window, $$rAF, $q, imageService) {

    function CropService(canvas, options) {
        if (!canvas) throw new Error("No canvas argument.");
        if (!options) throw new Error("No options argument.");

        var self = this;
        this.canvas = canvas;
        this.ctx = canvas.getContext('2d');
        this.radius = 0;
        this.options = options;
        this.disposed = false;

        this.bindHammer();
        this.animationLoop();

        if (options.image) this.initFromBuffer(options.image);
        else if (options.src) this.initFromSrc(options.src);
    };

    CropService.prototype.bindHammer = function () {

        var mc = new Hammer.Manager(this.canvas, {
            domEvents: true
        });
        mc.add(new Hammer.Pan({ threshold: 0, pointers: 0 }));
        mc.add(new Hammer.Swipe()).recognizeWith(mc.get('pan'));
        mc.add(new Hammer.Rotate({ threshold: 0 })).recognizeWith(mc.get('pan'));
        mc.add(new Hammer.Pinch({ threshold: 0 })).recognizeWith([mc.get('pan'), mc.get('rotate')]);
        mc.add(new Hammer.Tap({ event: 'doubletap', taps: 2 }));
        mc.add(new Hammer.Tap());

        mc.on("panstart panmove", this.onPan.bind(this));
        mc.on("pinchstart pinchmove", this.onPinch.bind(this));
        mc.on("hammer.input", this.onInput.bind(this));
    };

    CropService.prototype.eventToPoint = function (ev, index) {
        index = index || 0;
        var rect = this.canvas.getBoundingClientRect();
        var pointer = ev.pointers[index];
        var x = pointer.clientX - rect.left;
        var y = pointer.clientY - rect.top;

        if (ev.type == "panstart") {
            x -= ev.deltaX;
            y -= ev.deltaY;
        }

        return new Point(x, y);
    };

    CropService.prototype.onInput = function (ev) {
        if (ev.isFinal) {
            this.theSelection.onUp();
            this.refresh = true;
        }
    };

    CropService.prototype.onPan = function (ev) {
        if (ev.type == "panstart") this.theSelection.onDown(this.eventToPoint(ev));
        this.theSelection.onMove(this.eventToPoint(ev));
        this.refresh = true;
    };

    CropService.prototype.onPinch = function (ev) {
        if (ev.type == "pinchstart") {
            this.theSelection.onDown(this.eventToPoint(ev, 0));
            this.theSelection.onDown(this.eventToPoint(ev, 1));
        }
        this.refresh = true;
    };


    CropService.prototype.calculateCanvasSize = function (width, ratio) {
        this.canvas.width = width;
        this.canvas.height = width / ratio;

        //console.log("calculate height: ", width, ratio, " => ", this.canvas.height);

        if ((window.innerHeight - 150) < this.canvas.height) {
            this.canvas.height = window.innerHeight - 150;
            this.canvas.width = this.canvas.height * ratio;
            //console.log("height truncated: ", this.canvas.width, this.canvas.height);
        }
    }

    CropService.prototype.initFromSrc = function (src) {
        var self = this;

        return imageService.create(src).then(function (image) {
            return self.initFromBuffer();
        });
    };

    CropService.prototype.initFromBuffer = function (image) {
        var self = this;
        self.image = image;
        var imageRatio = self.image.width / self.image.height;

        self.options.ratio = self.options.ratio || imageRatio;

        var defaultWidth = Math.min(window.innerWidth, 960) - 16;
        var width = Math.min(self.image.width, defaultWidth); /**/

        self.calculateCanvasSize(width, imageRatio);

        return self.resize(self.image, self.canvas.width, self.canvas.height).then(function (image) {

            self.original = {
                canvasImage: image
            }
            self.canvasImage = image;

            return self.setDefaultSelection().then(function () {
                self.refresh = true;
            });
        });
    };

    CropService.prototype.setDefaultSelection = function () {
        var self = this;

        return $timeout(function () {
            var w = Math.max(Math.min(self.canvasImage.width, 80), 40);

            var h = w / self.options.ratio;
            if (h > self.canvasImage.height) {
                var h = Math.max(Math.min(self.canvasImage.height, 80), 40);
                var w = h * self.options.ratio;
            }
            self.theSelection = new Selection({ ctx: self.ctx, w: w, h: h, ratio: self.options.ratio });
        });
    };

    CropService.prototype.animationLoop = function () {
        if (this.disposed) return;
        $$rAF(this.animationLoop.bind(this));
        if (this.refresh) {
            this.draw();
            this.refresh = false;
        }
    };

    CropService.prototype.dispose = function () {
        this.disposed = true;
    };

    CropService.prototype.draw = function () {

        this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); // clear canvas
        this.ctx.drawImage(this.canvasImage, 0, 0);

        // and make it darker
        this.ctx.fillStyle = 'rgba(0, 0, 0, 0.7)';
        this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);

        var position = this.theSelection.position();

        this.ctx.clearRect(position.x, position.y, position.w, position.h); // clear canvas
        this.ctx.drawImage(this.canvasImage, position.x, position.y, position.w, position.h, position.x, position.y, position.w, position.h);

        this.theSelection.draw();
    };

    CropService.prototype.createCropCanvas = function (position) {
        var temp_canvas = document.createElement('canvas');
        var temp_ctx = temp_canvas.getContext('2d');

        temp_canvas.width = position.w;
        temp_canvas.height = position.h;

        if (this.options.maxWidth && temp_canvas.width > this.options.maxWidth) {
            var ratio = position.w / position.h;
            temp_canvas.width = this.options.maxWidth;
            temp_canvas.height = temp_canvas.width / ratio;
        }
        else if (this.options.width) {
            var ratio = position.w / position.h;
            temp_canvas.width = this.options.width;
            temp_canvas.height = temp_canvas.width / ratio;
        }

        return temp_ctx;
    };

    CropService.prototype.crop = function () {
        var self = this;
        var temp_ctx = null;

        if (self.radius == 0) {
            var position1 = self.theSelection.position();
            temp_ctx = self.createCropCanvas(position1);

            self.theSelection.scale(self.image.width / self.canvasImage.width);
            var position = self.theSelection.position();
            temp_ctx.drawImage(self.image, position.x, position.y, position.w, position.h, 0, 0, temp_ctx.canvas.width, temp_ctx.canvas.height);
        }

        if (self.radius == 180) {
            //DEBUG replace temp_ctx by this.ctx
            var position1 = self.theSelection.position();
            temp_ctx = self.createCropCanvas(position1);

            //this.canvas.width = temp_ctx.canvas.width;
            //this.canvas.height = temp_ctx.canvas.height;

            temp_ctx.rotate(self.radius * Math.PI / 180);
            temp_ctx.translate(-temp_ctx.canvas.width, -temp_ctx.canvas.height);

            self.theSelection.rotate(self.radius, new Point(0, 0));
            self.theSelection.translate(new Point(this.canvasImage.width, this.canvasImage.height));
            self.theSelection.scale(self.image.width / self.canvasImage.width);
            var position = self.theSelection.position();
            temp_ctx.drawImage(self.image, position.x, position.y, position.w, position.h, 0, 0, temp_ctx.canvas.width, temp_ctx.canvas.height);
        }

        if (self.radius == 90) {
            //DEBUG replace temp_ctx by this.ctx
            var position1 = self.theSelection.position();
            temp_ctx = self.createCropCanvas(position1);

            //this.canvas.width = temp_ctx.canvas.width;
            //this.canvas.height = temp_ctx.canvas.height;

            temp_ctx.rotate(self.radius * Math.PI / 180);
            temp_ctx.translate(0, -temp_ctx.canvas.width);

            self.theSelection.rotate(270, new Point(0, 0));
            self.theSelection.translate(new Point(0, self.canvasImage.width));
            self.theSelection.scale(self.image.height / self.canvasImage.width); 
            var position = self.theSelection.position();

            temp_ctx.drawImage(self.image, position.x, position.y, position.w, position.h, 0, 0, temp_ctx.canvas.height, temp_ctx.canvas.width);
        }

        if (self.radius == 270) {
            //DEBUG replace temp_ctx by this.ctx
            var position1 = self.theSelection.position();
            temp_ctx = self.createCropCanvas(position1);

            //this.canvas.width = temp_ctx.canvas.width;
            //this.canvas.height = temp_ctx.canvas.height;

            temp_ctx.rotate(self.radius * Math.PI / 180);
            temp_ctx.translate(-temp_ctx.canvas.height, 0);

            self.theSelection.rotate(90, new Point(0, 0));
            self.theSelection.translate(new Point(this.canvasImage.height, 0));
            self.theSelection.scale(self.image.height / self.canvasImage.width); 
            var position = self.theSelection.position();

            temp_ctx.drawImage(self.image, position.x, position.y, position.w, position.h, 0, 0, temp_ctx.canvas.height, temp_ctx.canvas.width);
        }

        var dataUrl = temp_ctx.canvas.toDataURL("image/jpeg", 0.8);
        if (self.oncrop) {
            self.oncrop(dataUrl); //callback function
        }
    };


    CropService.prototype.resize = function (image, w, h) {
        var self = this;
        return $timeout(function () {
            var temp_canvas = document.createElement('canvas');
            var temp_ctx = temp_canvas.getContext('2d');

            temp_canvas.width = w;
            temp_canvas.height = h;
            temp_ctx.drawImage(image, 0, 0, image.width, image.height, 0, 0, w, h);
            return temp_canvas.toDataURL("image/png");

        }).then(function (dataUri) {
            return imageService.create(dataUri).then(function (r) {
                console.log("resize image:", image.width, image.height, " to ", w, h, " => ", r.width, r.height);
                return r;
            });
        });
    };

    CropService.prototype.rotateRight = function () {
        var self = this;

        //self.theSelection.rotate(90, new Point(this.ctx.canvas.width / 2, this.ctx.canvas.height / 2));
        //self.refresh = true;

        self.radius = (self.radius + 90) % 360;
        return self.rotateCanvasImage(this.radius).then(function () {
            return self.setDefaultSelection().then(function () {
                self.refresh = true;
            });
        });
    };

    CropService.prototype.rotateLeft = function () {
        var self = this;
        //self.theSelection.rotate(-90, new Point(this.ctx.canvas.width / 2, this.ctx.canvas.height / 2));
        //self.refresh = true;

        self.radius = (self.radius + 270) % 360;
        return self.rotateCanvasImage(this.radius).then(function () {
            return self.setDefaultSelection().then(function () {
                self.refresh = true;
            });
        });
    };

    CropService.prototype.rotateCanvasImage = function (radius) {
        var self = this;

        return $timeout(function () {
            var temp_canvas = document.createElement('canvas');
            var temp_ctx = temp_canvas.getContext('2d');

            var ratio = self.canvas.height / self.canvas.width; // inverse ratio

            self.calculateCanvasSize(self.original.canvasImage.width, ratio);

            temp_canvas.height = self.canvas.height;
            temp_canvas.width = self.canvas.width;

            temp_ctx.rotate(radius * Math.PI / 180);
            if (radius == 270) {
                var scale = self.canvas.height / self.original.canvasImage.width;
                temp_ctx.scale(scale, scale);
                temp_ctx.translate(-self.original.canvasImage.width, 0);
                temp_ctx.drawImage(self.original.canvasImage, 0, 0);
            }
            else if (radius == 180) {
                temp_ctx.translate(-self.original.canvasImage.width, -self.original.canvasImage.height);
                temp_ctx.drawImage(self.original.canvasImage, 0, 0);
            }
            else if (radius == 90) {
                var scale = self.canvas.height / self.original.canvasImage.width;
                temp_ctx.scale(scale, scale);
                temp_ctx.translate(0, -self.original.canvasImage.height);
                temp_ctx.drawImage(self.original.canvasImage, 0, 0);
            }
            else
                temp_ctx.drawImage(self.original.canvasImage, 0, 0);

            return temp_canvas.toDataURL("image/png");

        }).then(function (dataUri) {
            return imageService.create(dataUri).then(function (image) {
                self.canvasImage = image;
                console.log("image left:", image.width, image.height);
            });
        });
    };

    /*--------------*/

    function Point(x, y) {
        this.x = x;
        this.y = y;
    };

    Point.prototype.translate = function (point) {
        this.x = point.x + this.x;
        this.y = point.y + this.y;
        return this;
    };

    Point.prototype.rotate = function (angle, point) {
        var a = angle * Math.PI / 180.0;
        var cosa = Math.cos(a);
        var sina = Math.sin(a);
        var pointX = this.x;
        var pointY = this.y;
        var newX = Math.round(cosa * (pointX - point.x) - sina * (pointY - point.y) + point.x);
        var newY = Math.round(sina * (pointX - point.x) + cosa * (pointY - point.y) + point.y);
        //console.log("rotate", angle, "center x:", x, "y:", y, "| x:", pointX, "=>", newX, "y:", pointY, "=>", newY);
        this.x = newX;
        this.y = newY;
        return this;
    }

    Point.prototype.axialSym = function (point) {
        var pointX = this.x;
        var pointY = this.y;

        var symX = 2 * point.x - pointX;
        var symY = 2 * point.y - pointY;

        this.x = symX;
        this.y = symY;

        return this;
    }


    Point.prototype.equals = function (point) {
        return this.x == point.x && this.y == point.y;
    };

    Point.prototype.isOnTopLeft = function (point) {
        return this.x <= point.x && this.y <= point.y;
    };

    Point.prototype.isOnBottomRight = function (point) {
        return this.x >= point.x && this.y >= point.y;
    };

    Point.prototype.distance = function (point) {
        return new Point(point.x - this.x, point.y - this.y);
    };

    Point.prototype.rationalize = function (ratio, sens) {
        if (ratio == null) return;
        if (Math.abs(this.x) >= Math.abs(this.y))
            this.rationalizeY(ratio, sens);
        else
            this.rationalizeX(ratio, sens);
    };

    Point.prototype.rationalizeX = function (ratio, sens) {
        if (ratio == null) return;
        this.x = ratio * this.y * sens;
    };

    Point.prototype.rationalizeY = function (ratio, sens) {
        if (ratio == null) return;
        this.y = this.x / ratio * sens;
    };

    /*--------------*/

    function Position(x, y, x2, y2) {
        this.x = x;
        this.x2 = x2;
        this.y = y;
        this.y2 = y2;
        this.w = this.x2 - this.x;
        this.h = this.y2 - this.y;
    }

    Position.prototype.absolute = function () {
        this.x = Math.abs(this.x);
        this.y = Math.abs(this.y);
        this.x2 = Math.abs(this.x2);
        this.y2 = Math.abs(this.y2);
        this.w = Math.abs(this.w);
        this.h = Math.abs(this.h);
    }

    Position.prototype.scale = function (value) {
        this.x = this.x * value;
        this.y = this.y * value;
        this.x2 = this.x2 * value;
        this.y2 = this.y2 * value;
        this.w = this.w * value;
        this.h = this.h * value;
    };

    /*--------------*/

    function Rectangle(ctx, topLeft, bottomRight) {
        this.ctx = ctx;
        this.topLeft = topLeft;
        this.bottomRight = bottomRight;
        this.focus = false;
    };

    Rectangle.prototype.scale = function (value) {
        this.topLeft.x = this.topLeft.x * value;
        this.topLeft.y = this.topLeft.y * value;
        this.bottomRight.x = this.bottomRight.x * value;
        this.bottomRight.y = this.bottomRight.y * value;
    };

    Rectangle.prototype.contains = function (point) {
        return point.isOnTopLeft(this.bottomRight) && point.isOnBottomRight(this.topLeft);
    };

    Rectangle.prototype.updateFocus = function (point) {
        if (point == null) this.focus = false;
        else this.focus = this.contains(point);
    };

    Rectangle.prototype.draw = function () {
    };

    Rectangle.prototype.rotate = function (angle, point) {
        this.topLeft.rotate(angle, point);
        this.bottomRight.rotate(angle, point);
        return this;
    };

    Rectangle.prototype.flipH = function (x) {
        this.topLeft.axialSym(new Point(x, this.topLeft.y));
        this.bottomRight.axialSym(new Point(x, this.bottomRight.y));
        return this;
    };

    Rectangle.prototype.translate = function (point) {
        this.topLeft.translate(point);
        this.bottomRight.translate(point);
        return this;
    };

    Rectangle.prototype.translateTopRight = function (point) {
        this.topLeft.translate(new Point(0, point.y));
        this.bottomRight.translate(new Point(point.x, 0));
        return this;
    };

    Rectangle.prototype.translateTopLeft = function (point) {
        this.topLeft.translate(point);
        return this;
    };

    Rectangle.prototype.translateBottomRight = function (point) {
        this.bottomRight.translate(point);
        return this;
    };

    Rectangle.prototype.translateBottomLeft = function (point) {
        this.topLeft.translate(new Point(point.x, 0));
        this.bottomRight.translate(new Point(0, point.y));
        return this;
    };

    Rectangle.prototype.position = function () {
        return new Position(this.topLeft.x, this.topLeft.y, this.bottomRight.x, this.bottomRight.y);
    };

    /*--------------*/

    function StrikeRectangle(ctx, topLeft, bottomRight) {
        Rectangle.call(this, ctx, topLeft, bottomRight);
    };

    StrikeRectangle.prototype = Object.create(Rectangle.prototype);
    StrikeRectangle.prototype.constructor = StrikeRectangle;

    StrikeRectangle.prototype.draw = function () {
        var position = this.position();
        this.ctx.strokeStyle = 'rgb(255,255,255)';
        this.ctx.lineWidth = 2;
        this.ctx.strokeRect(position.x, position.y, position.w, position.h);

    };
    /*--------------*/

    function FillRectangle(ctx, topLeft, bottomRight) {
        Rectangle.call(this, ctx, topLeft, bottomRight);
    };

    FillRectangle.prototype = Object.create(Rectangle.prototype);
    FillRectangle.prototype.constructor = FillRectangle;

    FillRectangle.prototype.draw = function () {
        var position = this.position();

        var minus = 10;
        if (this.focus) this.ctx.fillStyle = "#0094FF";
        else this.ctx.fillStyle = 'rgb(255,255,255)';
        this.ctx.fillRect(position.x + minus, position.y + minus, position.w - (minus * 2), position.h - (minus * 2));

        this.ctx.lineWidth = 1;
        this.ctx.strokeStyle = 'rgb(255,255,255)';
        this.ctx.strokeRect(position.x + minus, position.y + minus, position.w - (minus * 2), position.h - (minus * 2));
    };

    /*--------------*/

    function Selection(options) {
        this.ctx = options.ctx;
        this.ratio = options.ratio;
        this.cursor = null;
        this._focus = false;

        var shiftX = options.w / 2.0;
        var shiftY = options.h / 2.0;
        var x = (this.ctx.canvas.clientWidth - options.w) / 2.0;
        var y = (this.ctx.canvas.clientHeight - options.h) / 6.0;


        this.topRight = new FillRectangle(this.ctx, new Point(x + shiftX - 20, y - shiftY - 20), new Point(x + shiftX + 20, y - shiftY + 20));
        this.topLeft = new FillRectangle(this.ctx, new Point(x - shiftX - 20, y - shiftY - 20), new Point(x - shiftX + 20, y - shiftY + 20));
        this.bottomRight = new FillRectangle(this.ctx, new Point(x + shiftX - 20, y + shiftY - 20), new Point(x + shiftX + 20, y + shiftY + 20));
        this.bottomLeft = new FillRectangle(this.ctx, new Point(x - shiftX - 20, y + shiftY - 20), new Point(x - shiftX + 20, y + shiftY + 20));

        this.rectangle = new StrikeRectangle(this.ctx, new Point(x - shiftX, y - shiftY), new Point(x + shiftX, y + shiftY));
    };

    Selection.prototype.draw = function () {
        this.rectangle.draw();
        this.topRight.draw();
        this.topLeft.draw();
        this.bottomRight.draw();
        this.bottomLeft.draw();
    };

    Selection.prototype.position = function () {
        return this.rectangle.position();
    };

    Selection.prototype.rotate = function (angle, point) {
        this.rectangle.rotate(angle, point);
        return this;
    };

    Selection.prototype.flipH = function (x) {
        this.rectangle.flipH(x);
        return this;
    };

    Selection.prototype.scale = function (value) {
        this.rectangle.scale(value);
        return this;
    };

    Selection.prototype.translate = function (point) {
        this.rectangle.translate(point);
        return this;
    };

    Selection.prototype.move = function (point) {

        if (this.rectangle.topLeft.y + point.y < 0) {
            point.y = 0 - this.rectangle.topLeft.y;
        }
        if (this.rectangle.topLeft.x + point.x < 0) {
            point.x = 0 - this.rectangle.topLeft.x;
        }
        if (this.rectangle.bottomRight.x + point.x > this.ctx.canvas.clientWidth) {
            point.x = this.ctx.canvas.clientWidth - this.rectangle.bottomRight.x;
        }
        if (this.rectangle.bottomRight.y + point.y > this.ctx.canvas.clientHeight) {
            point.y = this.ctx.canvas.clientHeight - this.rectangle.bottomRight.y;
        }

        this.rectangle.translate(point);
        this.topRight.translate(point);
        this.topLeft.translate(point);
        this.bottomRight.translate(point);
        this.bottomLeft.translate(point);
        return this;
    };

    Selection.prototype.moveTopRight = function (point) {
        point.rationalize(this.ratio, -1);

        if (this.rectangle.topLeft.y + point.y < 0) {
            point.y = 0 - this.rectangle.topLeft.y;
            point.rationalizeX(this.ratio, -1);
        }
        if (this.rectangle.bottomRight.x + point.x > this.ctx.canvas.clientWidth) {
            point.x = this.ctx.canvas.clientWidth - this.rectangle.bottomRight.x;
            point.rationalizeY(this.ratio, -1);
        }

        this.topRight.translate(point);
        this.topLeft.translate(new Point(0, point.y));
        this.bottomRight.translate(new Point(point.x, 0));
        this.rectangle.translateTopRight(point);
        return this;
    };

    Selection.prototype.moveTopLeft = function (point) {
        point.rationalize(this.ratio, 1);

        if (this.rectangle.topLeft.y + point.y < 0) {
            point.y = 0 - this.rectangle.topLeft.y;
            point.rationalizeX(this.ratio, -1);
        }

        if (this.rectangle.topLeft.x + point.x < 0) {
            point.x = 0 - this.rectangle.topLeft.x;
            point.rationalizeY(this.ratio, -1);
        }

        this.topLeft.translate(point);
        this.topRight.translate(new Point(0, point.y));
        this.bottomLeft.translate(new Point(point.x, 0));
        this.rectangle.translateTopLeft(point);
        return this;
    };

    Selection.prototype.moveBottomRight = function (point) {
        point.rationalize(this.ratio, 1);

        if (this.rectangle.bottomRight.y + point.y > this.ctx.canvas.clientHeight) {
            point.y = this.ctx.canvas.clientHeight - this.rectangle.bottomRight.y;
            point.rationalizeX(this.ratio, 1);
        }
        if (this.rectangle.bottomRight.x + point.x > this.ctx.canvas.clientWidth) {
            point.x = this.ctx.canvas.clientWidth - this.rectangle.bottomRight.x;
            point.rationalizeY(this.ratio, 1);
        }

        this.bottomRight.translate(point);
        this.bottomLeft.translate(new Point(0, point.y));
        this.topRight.translate(new Point(point.x, 0));
        this.rectangle.translateBottomRight(point);
        return this;
    };

    Selection.prototype.moveBottomLeft = function (point) {
        point.rationalize(this.ratio, -1);

        if (this.rectangle.bottomRight.y + point.y > this.ctx.canvas.clientHeight) {
            point.y = this.ctx.canvas.clientHeight - this.rectangle.bottomRight.y;
            point.rationalizeX(this.ratio, -1);
        }

        if (this.rectangle.topLeft.x + point.x < 0) {
            point.x = 0 - this.rectangle.topLeft.x;
            point.rationalizeY(this.ratio, -1);
        }

        this.bottomLeft.translate(point);
        this.bottomRight.translate(new Point(0, point.y));
        this.topLeft.translate(new Point(point.x, 0));
        this.rectangle.translateBottomLeft(point);
        return this;
    };

    Selection.prototype.onDown = function (point) {
        this.cursor = point;
        this.topRight.updateFocus(point);
        this.topLeft.updateFocus(point);
        this.bottomRight.updateFocus(point);
        this.bottomLeft.updateFocus(point);
    };

    Selection.prototype.onMove = function (point) {
        this.shift = this.cursor.distance(point);

        if (this.bottomRight.focus)
            this.moveBottomRight(this.shift);
        else if (this.topRight.focus)
            this.moveTopRight(this.shift);
        else if (this.bottomLeft.focus)
            this.moveBottomLeft(this.shift);
        else if (this.topLeft.focus)
            this.moveTopLeft(this.shift);
        else
            this.move(this.shift);

        this.cursor = point;
    };

    Selection.prototype.onUp = function () {
        this.topRight.updateFocus(null);
        this.topLeft.updateFocus(null);
        this.bottomRight.updateFocus(null);
        this.bottomLeft.updateFocus(null);
        this.cursor = null;
    };

    return CropService;

} ]);